package servlet;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class WebappClassLoader extends ClassLoader {

    private String classes;
    private String lib;

    public WebappClassLoader(String basePath) {
        /*this.classes = basePath + "/WEB-INF/classes/";
        this.lib = basePath + "/WEB-INF/lib/";*/
        this.classes = basePath + "/";
        this.lib = basePath + "/WEB-INF/lib/";
    }

    /*@Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] bytes = null;
        //Path path = Path.of(classes + name.replace('.', '/') + ".class");
        String path=classes + name.replace('.', '/') + ".class";
        File file = new File(path);
        if (!file.exists()) {
            try {
                //bytes = Files.readAllBytes(path);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            bytes = findClassFromLib(name);
        }
        if (bytes == null) {
            throw new ClassNotFoundException();
        }
        return defineClass(name, bytes, 0, bytes.length);
    }

    private byte[] findClassFromLib(String name) {
        File[] libFiles = new File(lib).listFiles();
        if (libFiles == null || libFiles.length <= 0) {
            return null;
        }
        for (File file : libFiles) {
            if (file.isFile() && file.getName().endsWith(".jar")) {
                byte[] bytes = new byte[0];
                try {
                    bytes = findClassFromJar(new JarFile(file), name);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (bytes != null) {
                    return bytes;
                }
            }
        }
        return null;
    }

    private byte[] findClassFromJar(JarFile jar, String name) throws IOException {
        Enumeration<JarEntry> entries = jar.entries();
        while (entries.hasMoreElements()) {
            JarEntry jarEntry = entries.nextElement();
            String entryName = jarEntry.getName();
            if (entryName.endsWith(".class")) {
                String className = entryName.replace(".class", "").replace("/", ".");
                if (!className.equals(name)) {
                    continue;
                }
                InputStream inputStream = jar.getInputStream(jarEntry);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                byte[] buffer = new byte[4096];
                int bytesNumRead = 0;
                while ((bytesNumRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesNumRead);
                }
                byte[] bytes = outputStream.toByteArray();
                inputStream.close();
                return bytes;
            }
        }
        return null;
    }*/
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException{
        try {
            byte [] classDate=getData(name);
            if(classDate==null){}
            else{
                //defineClass方法将字节码转化为类
                return defineClass(name,classDate,0,classDate.length); }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return super.findClass(name);
    }


    //返回类的字节码
    private byte[] getData(String className) throws IOException{
        InputStream in = null;
        ByteArrayOutputStream out = null;
        String path=classes + File.separatorChar + className.replace('.',File.separatorChar)+".class";
        try {
            in=new FileInputStream(path);
            out=new ByteArrayOutputStream();
            byte[] buffer=new byte[2048];
            int len=0;
            while((len=in.read(buffer))!=-1){
                out.write(buffer,0,len);
            }
            return out.toByteArray();
        }
        catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally{
            in.close();
            out.close();
        }
        return null;
    }

}
